#ifndef xpack_test_lang_cxx_format
#define xpack_test_lang_cxx_format
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::test_lang_cxx_format::inc
#include"test/helper.hpp" // 需要放第一
#include"configure/limit.hpp"
#include"lang/cxx/format.hpp"
#include"lang/cxx/parse.hpp"
#include"lang/cxx.hpp"
#include"memop/copy.hpp"
#pragma pop_macro("xuser")

namespace mixc::test_lang_cxx_format{
    xstruct(
        xname(prop),
        xprif(m_mf32, f32),
        xprif(m_mf64, f64),
        xprif(m_mu08, u08),
        xprif(m_mu16, u16),
        xprif(m_mu32, u32),
        xprif(m_mu64, u64),
        xprif(m_mi08, i08),
        xprif(m_mi16, i16),
        xprif(m_mi32, i32),
        xprif(m_mi64, i64),
        xprif(m_mchar, char),
        xprif(m_masciis, asciis)
    )
        xprops()
            xpubget_pubset(mf32, f32);
            xpubget_pubset(mf64, f64);
            xpubget_pubset(mu08, u08);
            xpubget_pubset(mu16, u16);
            xpubget_pubset(mu32, u32);
            xpubget_pubset(mu64, u64);
            xpubget_pubset(mi08, i08);
            xpubget_pubset(mi16, i16);
            xpubget_pubset(mi32, i32);
            xpubget_pubset(mi64, i64);
            xpubget_pubset(mchar, char);
            xpubget_pubset(masciis, asciis);
        $

        xprops_operator()
    $

    xtest("format"){
        char        buffer_a[1024];
        char        buffer_b[1024];
        char *      ptr_b;
        inc::c08    value_a;
        inc::c08    value_b;

        auto stream = [&](const char * content, uxx length){
            inc::copy_unsafe(ptr_b, content, length);
            ptr_b += length;
        };

        #define xgen(fmt,...)                                                       \
        value_a = inc::c08{fmt}.format(__VA_ARGS__, [&](uxx){                       \
            return buffer_a;                                                        \
        });                                                                         \
                                                                                    \
        ptr_b = buffer_b;                                                           \
        inc::c08{fmt}.format(__VA_ARGS__, stream);                                  \
        value_b = inc::c08(buffer_b, ptr_b - buffer_b)

        #define xgen_assert_eq(VAL)     \
            xassert_eq(value_a, VAL);   \
            xassert_eq(value_b, VAL)

        // 杂项测试
        xgen("\v", 1);
        xgen_assert_eq("1");

        xgen("\v", 1.5f);
        xgen_assert_eq("1.5");

        xgen("\v", 1.25f);
        xgen_assert_eq("1.25");

        xgen("\v", 1.5);
        xgen_assert_eq("1.5");

        xgen("\v", 1.25);
        xgen_assert_eq("1.25");

        xgen("\v", 'a');
        xgen_assert_eq("a");

        xgen("\v", '\v');
        xgen_assert_eq("\v");

        xgen("\v", sizeof(0));
        xgen_assert_eq("4");

        xgen("\v", "1024 love");
        xgen_assert_eq("1024 love");

        enum{
            enum_0,
            enum_1 = -1,
            enum_2 = -2,
        };

        enum : u08{
            enum_3 = 1,
            enum_4 = 2,
            enum_5 = u08(-1),
        };

        enum class foo{
            enum_0,
        };

        xgen("\v \v \v", enum_0, enum_1, enum_2);
        xgen_assert_eq("0 -1 -2");

        xgen(" \v\v\v", enum_3, enum_4, enum_5);
        xgen_assert_eq(" 12255");

        xgen("enum:\v", foo::enum_0);
        xgen_assert_eq("enum:0");

        xgen("^\v^", "~");
        xgen_assert_eq("^~^");

        xgen("(#^\v^#)/~", '_', 88);
        xgen_assert_eq("(#^_^#)/~88");

        xgen("\v", inc::c08{ "你好世界" });
        xgen_assert_eq("你好世界");

        prop bar;
        bar->mf32 = 1;
        bar->mf64 = 1;
        bar->mu08 = 255;
        bar->mu16 = 1;
        bar->mu32 = 1;
        bar->mu64 = 1;
        bar->mi08 = -1;
        bar->mi16 = -1;
        bar->mi32 = -1;
        bar->mi64 = -1;
        bar->mchar = 'a';
        bar->masciis = "Hello World";
        xgen("\v", inc::h{bar->masciis});
        xgen_assert_eq("646c726f57206f6c6c6548");

        // 测试编译可以通过，支持属性
        xgen("\v \v \v \v \v \v \v \v \v \v \v \v", inc::v{bar->mf32}, inc::v{bar->mf64}, inc::v{bar->mu08}, inc::v{bar->mu16}, inc::v{bar->mu32}, inc::v{bar->mu64}, inc::v{bar->mi08}, inc::v{bar->mi16}, inc::v{bar->mi32}, inc::v{bar->mi64}, inc::v{bar->mchar}, inc::v{bar->masciis});
        xgen_assert_eq("1 1 255 1 1 1 -1 -1 -1 -1 a Hello World");

        xgen("\v", inc::vl{bar->mf32, bar->mf64, bar->mu08, bar->mu16, bar->mu32, bar->mu64, bar->mi08, bar->mi16, bar->mi32, bar->mi64, bar->mchar, bar->masciis});
        xgen_assert_eq("11255111-1-1-1-1aHello World");

        // 测试编译可以通过，支持属性
        xgen("\v \v \v \v \v \v \v \v \v \v \v \v", inc::h{bar->mf32}, inc::h{bar->mf64}, inc::h{bar->mu08}, inc::h{bar->mu16}, inc::h{bar->mu32}, inc::h{bar->mu64}, inc::h{bar->mi08}, inc::h{bar->mi16}, inc::h{bar->mi32}, inc::h{bar->mi64}, inc::h{bar->mchar}, inc::h{bar->masciis});
        xgen_assert_eq("3f800000 3ff0000000000000 ff 1 1 1 ff ffff ffffffff ffffffffffffffff 61 646c726f57206f6c6c6548");

        xgen("\v \v", inc::f{bar->mf32}, inc::f{bar->mf64});
        xgen_assert_eq("1 1");

        xgen("\v \v", inc::e{bar->mf32}, inc::e{bar->mf64});
        xgen_assert_eq("1e000 1e000");

        // 测试整数符号
        xgen("v:\v v:\v v:\v", inc::v{ 1 }.s(true), inc::v{ 0 }.s(true), inc::v{ -1 }.s(true));
        xgen_assert_eq("v:+1 v:+0 v:-1");



        // 测试十六进制
        xgen("h:\v \v \v\v", inc::h{ 0x1314 }, inc::h{ '\n' }, inc::h{ 0x0 }, inc::h{ 0x0123 }.r(4));
        xgen_assert_eq("h:1314 a 0 123");

        xgen("h:\v \v \v", inc::h{ 0x1000f }, inc::h{ 0xf0000000 }, inc::h{ 0x0f000000 });
        xgen_assert_eq("h:1000f f0000000 f000000");

        xgen("zh:\v \v \v \v \v \v", inc::zh{ 0x1314 }, inc::zh{ '\n' }, inc::zh{ 1.25f }, inc::zh{ 1.5 }, inc::zh{ 0x0 }, inc::zh{ 0x0123 }.r(4));
        xgen_assert_eq("zh:00001314 0a 3fa00000 3ff8000000000000 00000000 00000123");

        xgen("zhs:\v \v \v \v \v \v", inc::zhs{ 0x1234567890abcdefull }, inc::zhs{ '\n' }, inc::zhs{ 1.25f }, inc::zhs{ 1.5 }, inc::zhs{ 0x0 }, inc::zhs{ 0x0123 }.r(4));
        xgen_assert_eq("zhs:1234567890abcdefh 0ah 3fa00000h 3ff8000000000000h 00000000h 00000123h");

        xgen("H:\v \v \v\v", inc::H{ 0x1314f }, inc::H{ '\n' }, inc::H{ 0x0 }, inc::H{ 0x0123 }.r(4));
        xgen_assert_eq("H:1314F A 0 123");

        xgen("zH:\v \v \v \v \v \v", inc::zH{ 0x1314f }, inc::zH{ '\n' }, inc::zH{ 1.25f }, inc::zH{ 1.5 }, inc::zH{ 0x0 }, inc::zH{ 0x0123 }.r(4));
        xgen_assert_eq("zH:0001314F 0A 3FA00000 3FF8000000000000 00000000 00000123");

        xgen("zHs:\v \v \v \v \v \v", inc::zHs{ 0x1234567890abcdefull }, inc::zHs{ '\n' }, inc::zHs{ 1.25f }, inc::zHs{ 1.5 }, inc::zHs{ 0x0 }, inc::zHs{ 0x0123 }.r(4));
        xgen_assert_eq("zHs:1234567890ABCDEFh 0Ah 3FA00000h 3FF8000000000000h 00000000h 00000123h");

        xgen("x:\v \v \v \v", inc::x{ 0x1234 }, inc::x{ '\n' }, inc::x{ 0x0 });
        xgen_assert_eq("x:0x1234 0xa 0x0 \\v");

        xgen("zx:\v \v \v \v \v \v", inc::zx{ 0x1314 }, inc::zx{ '\n' }, inc::zx{ 1.25f }, inc::zx{ 1.5 }, inc::zx{ 0x0 }, inc::zx{ 0x0123 }.l(9));
        xgen_assert_eq("zx:0x00001314 0x0a 0x3fa00000 0x3ff8000000000000 0x00000000 0x00000123 ");


        // 测试字符串十六进制化
        {
            char buf[] = "\n01234";

            xgen("h:\v \v \v", inc::h{ "" }, inc::h{ "\n01234" }, inc::h{ buf });
            xgen_assert_eq("h:0 34333231300a 34333231300a");

            xgen("zh:\v \v \v", inc::zh{ "" }, inc::zh{ "\n01234" }, inc::zh{ buf });
            xgen_assert_eq("zh:00 34333231300a 0034333231300a");

            xgen("zx:\v \v \v", inc::zx{ inc::c08("") }, inc::zx{ inc::c08("\n01234") }, inc::zx{ inc::c08(buf) });
            xgen_assert_eq("zx:0x00 0x34333231300a 0x34333231300a");
        }


        // 任意类型十六进制化
        struct ax{
            u64 a = 0x123456789abcdef0;
            u64 b = 0x0123456789abcdef;
        };

        xgen("h:\v", inc::h{ ax{} });
        xgen_assert_eq("h:123456789abcdef123456789abcdef0");

        xgen("zx:\v", inc::zx{ ax{} });
        xgen_assert_eq("zx:0x0123456789abcdef123456789abcdef0");




        // 测试科学计数法浮点数
        xgen("e:\v e:\v e:\v", inc::e{ -1.5e2 }, inc::e{ +1.25e2 }, inc::e{ 0.0 });
        xgen_assert_eq("e:-1.5e002 e:1.25e002 e:0e000");


        // 各个浮点模式基本测试
        xgen("\v \v", inc::e{ -1.5e2 }.mode(inc::float_format_t::fmt_1p2e3), inc::e{ +1.5e2 }.mode(inc::float_format_t::fmt_1p2e3));
        xgen_assert_eq("-1.5e002 1.5e002");

        xgen("\v \v", inc::e{ -1.25e26 }.mode(inc::float_format_t::fmt_s1p2e3), inc::e{ +1.5e-3 }.mode(inc::float_format_t::fmt_s1p2e3));
        xgen_assert_eq("-1.25e026 +1.5e-003");

        xgen("\v \v", inc::e{ -1.25e26 }.mode(inc::float_format_t::fmt_1p2es3), inc::e{ +1.25e-26 }.mode(inc::float_format_t::fmt_1p2es3));
        xgen_assert_eq("-1.25e+026 1.25e-026");

        xgen("\v \v", inc::e{ -1.25e26 }.mode(inc::float_format_t::fmt_s1p2es3), inc::e{ +1.25e26 }.mode(inc::float_format_t::fmt_s1p2es3));
        xgen_assert_eq("-1.25e+026 +1.25e+026");

        xgen("\v \v", inc::e{ -1.5e2 }.mode(inc::float_format_t::fmt_1p2E3), inc::e{ +1.5e2 }.mode(inc::float_format_t::fmt_1p2E3));
        xgen_assert_eq("-1.5E002 1.5E002");

        xgen("\v \v", inc::e{ -1.5e2 }.mode(inc::float_format_t::fmt_s1p2E3), inc::e{ +1.5e2 }.mode(inc::float_format_t::fmt_s1p2E3));
        xgen_assert_eq("-1.5E002 +1.5E002");

        xgen("\v \v", inc::e{ -1.5e2 }.mode(inc::float_format_t::fmt_1p2Es3), inc::e{ +1.5e-2 }.mode(inc::float_format_t::fmt_1p2Es3));
        xgen_assert_eq("-1.5E+002 1.5E-002");

        xgen("\v \v", inc::e{ -1.5e2 }.mode(inc::float_format_t::fmt_s1p2Es3), inc::e{ +1.5e-2 }.mode(inc::float_format_t::fmt_s1p2Es3));
        xgen_assert_eq("-1.5E+002 +1.5E-002");

        xgen("\v \v", inc::e{ -1.5e2 }.mode(inc::float_format_t::fmt_n), inc::e{ +1.5e-2 }.mode(inc::float_format_t::fmt_n));
        xgen_assert_eq("-150 0.015");

        xgen("\v \v \v", inc::e{ -1.25e4 }.mode(inc::float_format_t::fmt_sn), inc::e{ +1.125e0 }.mode(inc::float_format_t::fmt_sn), inc::e{ +1.5e-2 }.mode(inc::float_format_t::fmt_sn));
        xgen_assert_eq("-12500 +1.125 +0.015");

        xgen("\v \v \v", inc::f{ 123.543 }.precious(0), inc::f{ 123.543 }.precious(1), inc::f{ 123.546 }.precious(2));
        xgen_assert_eq("124 123.5 123.55");

        // 测试科学计数法浮点数的舍入
        xgen("e:\v e:\v e:\v e:\v", inc::e{ 1.245 }.precious(2), inc::e{ 1.245e10 }.precious(2), inc::e{ -1.2404e11 }.precious(3), inc::e{ 1.2451e-11 }.precious(2));
        xgen_assert_eq("e:1.25e000 e:1.25e010 e:-1.240e011 e:1.25e-011");

        xgen("e:\v e:\v e:\v e:\v", inc::e{ 0.0 }.precious(0), inc::e{ 0.0 }.precious(1), inc::e{ 0.0 }.precious(2), inc::e{ 0.0 }.precious(16));
        xgen_assert_eq("e:0e000 e:0.0e000 e:0.00e000 e:0.0000000000000000e000");

        xgen("e:\v e:\v", inc::e{ 9.95e10 }.precious(1), inc::e{ 9.94e10 }.precious(1));
        xgen_assert_eq("e:1.0e011 e:9.9e010");

        // 测试默认浮点显示规则
        xgen("\v \v \v \v \v \v \v", 1e20, 1e9, 0, 1.25, 1.125, 1.0625, 1e-5);
        xgen_assert_eq("1e020 1000000000 0 1.25 1.125 1.0625 0.00001");

        xgen("\v \v \v \v \v \v \v", -1e20, -1e9, 0, -1.25, -1.125, -1.0625, -1e-5);
        xgen_assert_eq("-1e020 -1000000000 0 -1.25 -1.125 -1.0625 -0.00001");

        // 测试右对齐
        xgen("hello", inc::v{ "world" }.r(6));
        xgen_assert_eq("hello world");

        xgen("\v", inc::v{ 1.25 }.r(6));
        xgen_assert_eq("  1.25");

        xgen("\v", inc::v{ 1.25 }.l(6));
        xgen_assert_eq("1.25  ");

        xgen("\v", inc::v{ 1.25 }.c(6));
        xgen_assert_eq(" 1.25 ");



        // 测试左对齐
        // 只按字节长度算
        xgen("\v\v", inc::v{ "C++ 从入门"/*4 + 3 * 3byte*/ }.l(14, '.').align_adjust(false), "到放弃");
        xgen_assert_eq("C++ 从入门.到放弃");

        xgen("\v\v", inc::v{ "C++ 从入门" }.l(13, '.').align_adjust(false), "到放弃");
        xgen_assert_eq("C++ 从入门到放弃");

        xgen("\v\v", inc::v{ "C++ 从入门" }.l(12, '.').align_adjust(false), "到入土为安");
        xgen_assert_eq("C++ 从入门到入土为安");


        // 测试左对齐
        xgen("\v\v", inc::v{ "C++ 从入门"/*4 + 3 * 3byte*/ }.l(11, '.'), "到放弃");
        xgen_assert_eq("C++ 从入门.到放弃");

        xgen("\v\v", inc::v{ "C++ 从入门" }.l(10, '.'), "到放弃");
        xgen_assert_eq("C++ 从入门到放弃");

        xgen("\v\v", inc::v{ "C++ 从入门" }.l(9, '.'), "到入土为安");
        xgen_assert_eq("C++ 从入门到入土为安");



        // 测试中间对齐
        xgen("\v\v", inc::v{ "SQL from rm -rf / to" }.c(32, ' ', '-'), ">escape");
        xgen_assert_eq("      SQL from rm -rf / to------>escape");



        // 超过栈上缓冲区大小
        xgen("\v", inc::v{ "loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong" });
        xgen_assert_eq("loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong");

        xgen("\v", inc::v{ "hello" }.l(130, '.'));
        xgen_assert_eq("hello.............................................................................................................................");

        xgen("\v", inc::v{ "hello" }.r(130, '.'));
        xgen_assert_eq(".............................................................................................................................hello");

        xgen("\v", inc::v{ "hello" }.c(130, '.'));
        xgen_assert_eq("..............................................................hello...............................................................");

        #undef  xgen

        enum : uxx{ max_buf = 128 };
        char buf[max_buf];
        auto alloc = [&](uxx length) -> char * {
            if (length >= max_buf){
                return nullptr;
            }
            return buf;
        };

        xassert_eq(inc::x{0x1234}.format(alloc), "0x1234");
        xassert_eq(inc::f{1.25}.r(6).format(alloc), "  1.25");
        xassert_eq(inc::f{1.25}.l(6).format(alloc), "1.25  ");
        xassert_eq(inc::f{1.25}.c(6).format(alloc), " 1.25 ");

        xassert_eq(inc::v{1.25}.r(6).format(alloc), "  1.25");
        xassert_eq(inc::v{1.25}.l(6).format(alloc), "1.25  ");
        xassert_eq(inc::v{1.25}.c(6).format(alloc), " 1.25 ");

        xassert_eq(inc::v{"miao"}.r(6).format(alloc), "  miao");
        xassert_eq(inc::v{"miao"}.l(6).format(alloc), "miao  ");
        xassert_eq(inc::v{"miao"}.c(6).format(alloc), " miao ");

        #undef xgen_assert_eq
    };
}

#endif
